/***************************************************************************************
 * Copyright (c) 2014-2024 Zihao Yu, Nanjing University
 *
 * NEMU is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 *PSL v2. You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 *KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 *NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *
 * See the Mulan PSL v2 for more details.
 ***************************************************************************************/

#include "common.h"
#include "debug.h"
#include "sdb.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

#define NR_WP 32

typedef struct watchpoint {
  int NO;
  struct watchpoint *next;

  /* TODO: Add more members if necessary */
  // 监视点就是用来，看变化，谁变化，我发现谁
  char expr[100];
  word_t new_value;
  word_t old_value;
} WP;

static WP wp_pool[NR_WP] = {};
static WP tail, *free_ = NULL;
// 这里有两个指针，一个头指针，一个猜测是尾巴。
// 这里是自由指针，用于遍历链表。

void init_wp_pool() { // 这里是初始化监视池---也就是提前开辟好的一些，
  int i;
  for (i = 0; i < NR_WP; i++) {
    wp_pool[i].NO = i; // 监视号从0依次增大，总共有 NR——WP个
    wp_pool[i].next = (i == NR_WP - 1 ? NULL : &wp_pool[i + 1]);
  }
  // tail->next = wp_pool;
  wp_pool[NR_WP - 1].next = &tail;

  free_ = wp_pool; // 这里自由的监视点，直接指向数组首个
}

/* TODO: Implement the functionality of watchpoint */

// 实现new_wp()

WP *new_wp() {
  if (free_ == &tail) {
    printf("Watchpoints totals %d.\n", NR_WP);

    return NULL;
  }
  WP *p = free_;       // 分配链表的头节点
  free_ = free_->next; // 更新free_指针，指向下一个空闲监视点
  p->next = NULL;      // 初始化该监视点的next指针为NULL
  return p;
}
void free_wp(WP *p) {
  p->next = free_; // 将释放的监视点插入到空闲链表的头部
  free_ = p;       // 更新空闲链表的头指针
}

void sdb_watchpoint_display() {
  bool flag = true;
  for (int i = 0; i < NR_WP  ; i++) {
    if (wp_pool[i].next == NULL) {
      printf(
          "Watchpoint No: %d, expr = \"%s\", old_value = %u, new_value = %u\n",
          wp_pool[i].NO, wp_pool[i].expr, wp_pool[i].old_value,
          wp_pool[i].new_value);
      flag = false;
    }
  }
  if (flag) {

    printf(" No watchpoint now.\n");
  }
}
void create_watchpoint(char *expr) {
  WP *p = new_wp();
  if (p == NULL) {
    return;
  }
  strcpy(p->expr, expr);
  p->old_value = 0;
  p->new_value = 0;
  printf("Created watchpoint No.%d successfully.\n", p->NO);
}
void delete_watchpoint(int no) {
  for (int i = 0; i < NR_WP; i++) {
    if (wp_pool[i].NO == no && wp_pool[i].next == NULL) {
      free_wp(&wp_pool[i]);
      printf("Deleted watchpoint No.%d successfully.\n", no);
      return;
    }
  }
  printf("Watchpoint No.%d not found.\n", no);
}
int update_watchpoint() {
  int n_changed = 0;
  for (int i = 0; i < NR_WP - 1; i++) {
    bool success = false;
    if (wp_pool[i].next == NULL) {
      word_t value = expr(wp_pool[i].expr, &success);
      Assert(success, "wrong expression %s\n", wp_pool[i].expr);
      if (value != wp_pool[i].new_value) {
        n_changed += 1; // 记录有几个监视点发生变化。
        printf("Watchpoint %d: %s\n", wp_pool[i].NO, wp_pool[i].expr);
        printf("				Old value = 0x%08x(%d)\n",
               wp_pool[i].new_value, wp_pool[i].new_value);
        printf("				New value = 0x%08x(%d)\n",
               value, value);
        wp_pool[i].old_value = wp_pool[i].new_value;
        wp_pool[i].new_value = value;
      }
    }
  }
  return n_changed;
}